package slimgo

import (
	"errors"
	"github.com/jesusslim/slimgo/templates"
	"github.com/jesusslim/slimgo/utils"
	"html/template"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var (
	tplFuncs template.FuncMap
	Tpls     map[string]*tplInfo
)

type tplInfo struct {
	file string //文件路径 区分大小写
	tpl  *template.Template
}

func init() {
	tplFuncs = make(template.FuncMap)
	Tpls = make(map[string]*tplInfo)

	//系统模板函数
	tplFuncs["Test"] = templates.Test
	tplFuncs["Date"] = templates.Date
}

/**
 * [AddTplFunc 添加模板函数]
 * @param {[type]} key      string        [函数名]
 * @param {[type]} funcname interface{} [函数体]
 */
func AddTplFunc(key string, funcname interface{}) {
	tplFuncs[key] = funcname
}

/**** build ****/

type tplFile struct {
	root  string
	files map[string][]string
}

func (this *tplFile) visit(path string, info os.FileInfo, err error) error {
	if info == nil {
		return err
	}
	if info.IsDir() || (info.Mode()&os.ModeSymlink) > 0 {
		return nil
	}
	if !strings.HasSuffix(path, ".html") {
		return nil
	}
	replacer := strings.NewReplacer("\\", "/")
	a := []byte(path)
	a = a[len([]byte(this.root)):]
	file := strings.TrimLeft(replacer.Replace(string(a)), "/")
	subdir := filepath.Dir(file)
	if _, ok := this.files[subdir]; ok {
		this.files[subdir] = append(this.files[subdir], file)
	} else {
		this.files[subdir] = []string{file}
	}
	return nil
}

func BuildTpl(dir string) error {
	if _, err := os.Stat(dir); err != nil {
		if os.IsNotExist(err) {
			return nil
		} else {
			return err
		}
	}
	tplFiles := &tplFile{
		root:  dir,
		files: make(map[string][]string),
	}
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		return tplFiles.visit(path, info, err)
	})
	if err != nil {
		return err
	}
	for _, v := range tplFiles.files {
		for _, f := range v {
			t, err := getTemplate(tplFiles.root, f, v...)
			if err != nil {
				Error("get tpl failed,", err.Error())
			} else {
				Tpls[strings.ToLower(f)] = &tplInfo{
					file: f,
					tpl:  t,
				}
			}
		}
	}
	return nil
}

func getSubTpls(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) {
	var fileabspath string
	if filepath.HasPrefix(file, "../") {
		fileabspath = filepath.Join(root, filepath.Dir(parent), file)
	} else {
		fileabspath = filepath.Join(root, file)
	}
	if !utils.FileExists(fileabspath) {
		return nil, [][]string{}, errors.New(fileabspath + " not found")
	}
	data, err := ioutil.ReadFile(fileabspath)
	if err != nil {
		return nil, [][]string{}, err
	}
	t, err = t.New(file).Parse(string(data))
	if err != nil {
		return nil, [][]string{}, err
	}
	reg := regexp.MustCompile(TplTagL + "[ ]*template[ ]+\"([^\"]+)\"")
	subs := reg.FindAllStringSubmatch(string(data), -1)
	for _, sub := range subs {
		if len(sub) == 2 {
			if t.Lookup(sub[1]) != nil {
				continue
			}
			if !strings.HasSuffix(sub[1], ".html") {
				continue
			}
			t, _, err = getSubTpls(root, sub[1], file, t)
			if err != nil {
				return nil, [][]string{}, err
			}
		}
	}
	return t, subs, nil
}

func getTemplate(root, file string, others ...string) (t *template.Template, err error) {
	t = template.New(file).Delims(TplTagL, TplTagR).Funcs(tplFuncs)
	t, _, err = getSubTpls(root, file, "", t)
	if err != nil {
		return nil, err
	}
	return
}
